﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Microsoft.Phone.Controls;

namespace ToyundaPhone.Pages
{
	public partial class SongListPage : PhoneApplicationPage, System.ComponentModel.INotifyPropertyChanged
	{
		private Helpers.SongListUpdater updater;
		private Microsoft.Phone.Shell.ProgressIndicator progressIndicator;
		private Helpers.SongEnumHelper songEnumHelper;
		private Helpers.PlaylistEnumHelper plEnumHelper;

		// Constructor
		public SongListPage()
		{
			InitializeComponent();
			progressIndicator = new Microsoft.Phone.Shell.ProgressIndicator() { IsVisible = false };
			Microsoft.Phone.Shell.SystemTray.SetProgressIndicator(this, progressIndicator);
			songEnumHelper = new Helpers.SongEnumHelper(e => Dispatcher.BeginInvoke(() => OnPropertyChanged("Songs")), songList);
			plEnumHelper = new Helpers.PlaylistEnumHelper(e => Dispatcher.BeginInvoke(() => OnPropertyChanged("Playlists")), songList);
		}

		private void Update_Click(object sender, EventArgs e)
		{
			if (updater == null)
			{
				InitUpdater();
			}
			updater.Start();
		}

		private void InitUpdater()
		{
			updater = new Helpers.SongListUpdater(new Uri(Application.Current.Resources["ListURL"] as string, UriKind.Absolute));
			updater.Database = (Application.Current as App).SongDatabase;
			updater.UpdateStarted += Updater_UpdateStart;
			updater.UpdateStateChanged += Updater_UpdateStateChanged;
			updater.UpdateProgressChanged += Updater_UpdateProgress;
			updater.UpdateFailed += Updater_UpdateFail;
			updater.UpdateCompleted += Updater_UpdateComplete;
		}

		private void Updater_UpdateStart(object sender, EventArgs e)
		{
			Dispatcher.BeginInvoke(() =>
			{
				progressIndicator.IsIndeterminate = true;
				progressIndicator.IsVisible = true;
				progressIndicator.Text = "Mise à jour en cours...";
				DisableAllControls();
			});
		}

		private void DisableAllControls()
		{
			foreach (var button in ApplicationBar.Buttons)
			{
				(button as Microsoft.Phone.Shell.ApplicationBarIconButton).IsEnabled = false;
			}
			foreach (var menu in ApplicationBar.MenuItems)
			{
				(menu as Microsoft.Phone.Shell.ApplicationBarMenuItem).IsEnabled = false;
			}
			this.IsEnabled = false;
		}

		private void Updater_UpdateStateChanged(object sender, Helpers.UpdateStateEventArgs e)
		{
			Dispatcher.BeginInvoke(() =>
			{
				switch (e.UpdateState)
				{
					case Helpers.UpdateState.Start:
						progressIndicator.IsIndeterminate = true;
						progressIndicator.Text = "Mise à jour en cours : démarrage (1/5)…";
						break;
					case Helpers.UpdateState.WebRequest:
						progressIndicator.IsIndeterminate = true;
						progressIndicator.Text = "Mise à jour en cours : connexion (2/5)…";
						break;
					case Helpers.UpdateState.Parse:
						progressIndicator.IsIndeterminate = false;
						progressIndicator.Value = 0;
						progressIndicator.Text = "Mise à jour en cours : importation (3/5)…";
						break;
					case Helpers.UpdateState.Commit:
						progressIndicator.IsIndeterminate = true;
						progressIndicator.Text = "Mise à jour en cours : enregistrement (4/5)…";
						break;
					case Helpers.UpdateState.Delete:
						progressIndicator.IsIndeterminate = true;
						progressIndicator.Text = "Mise à jour en cours : nettoyage (5/5)…";
						break;
				}
			});
		}

		private void Updater_UpdateProgress(object sender, Helpers.UpdateProgressEventArgs e)
		{
			Dispatcher.BeginInvoke(() =>
			{
				progressIndicator.Value = (double)e.BytesRead / (double)e.TotalBytes;
			});
		}

		private void Updater_UpdateFail(object sender, Helpers.UpdateStateEventArgs e)
		{
			Dispatcher.BeginInvoke(() =>
			{
				progressIndicator.IsVisible = false;
				EnableAllControls();
				MessageBox.Show("Mise à jour échoué à l'état : " + e.UpdateState.ToString() + ".", Application.Current.Resources["ApplicationName"] as string, MessageBoxButton.OK);
				if ((e.UpdateState != Helpers.UpdateState.Start) && (e.UpdateState != Helpers.UpdateState.WebRequest))
				{
					ReloadDatabase();
				}
			});
		}

		private void Updater_UpdateComplete(object sender, EventArgs e)
		{
			Dispatcher.BeginInvoke(() =>
			{
				progressIndicator.IsVisible = false;
				EnableAllControls();
				MessageBox.Show("Mise à jour terminée.", Application.Current.Resources["ApplicationName"] as string, MessageBoxButton.OK);
				Search_TextChanged(this, new EventArgs());
			});
		}

		private void EnableAllControls()
		{
			foreach (var button in ApplicationBar.Buttons)
			{
				(button as Microsoft.Phone.Shell.ApplicationBarIconButton).IsEnabled = true;
			}
			foreach (var menu in ApplicationBar.MenuItems)
			{
				(menu as Microsoft.Phone.Shell.ApplicationBarMenuItem).IsEnabled = true;
			}
			this.IsEnabled = true;
		}

		private void ReloadDatabase()
		{
			(Application.Current as App).ReloadDatabase();
			if (updater != null) updater.Database = (Application.Current as App).SongDatabase;
			Search_TextChanged(this, new EventArgs());
			Playlists = plEnumHelper.GetEnumerator();
			plEnumHelper.NotifyUpdate();
		}

		private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
		{
			if (Songs == null)
			{
				songList.EmptyText = "Chargement en cours…";
				Songs = songEnumHelper.GetEnumerator(from s in (Application.Current as App).SongDatabase.Songs orderby s.Work, s.Title select s);
				songEnumHelper.NotifyUpdate();
			}
			Playlists = plEnumHelper.GetEnumerator();
			plEnumHelper.NotifyUpdate();
			AskFirstUpdate();
		}

		private void AskFirstUpdate()
		{
			if (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Contains("FirstLoadDone")) return;
			CustomMessageBox cmb = new CustomMessageBox() {
				Caption = "Premier démarrage",
				Message = "Afin de pouvoir utiliser l'application, il vous faut télécharger la liste des morceaux depuis le serveur. Voulez-vous le faire maintenant ?\n\nCette opération nécessite l'utilisation de votre connexion de données.",
				LeftButtonContent = "Télécharger",
				RightButtonContent = "Plus tard",
			};
			cmb.Dismissed += (s, e) => {
				if (e.Result == CustomMessageBoxResult.LeftButton)
				{
					Update_Click(s, e);
				}
				System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Add("FirstLoadDone", true);
				System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Save();
			};
			cmb.Show();
		}

		private void Search_TextChanged(object sender, EventArgs e)
		{
			var predicate = ToyundaPhone.Helpers.PredicateBuilder.True<ToyundaPhone.Database.Song>();
			foreach (var keyword in (Application.Current as App).SongDatabase.WordExtractor.GetWords(Search.Text).Select(w => " " + w))
			{
				var tmpKeyword = keyword;
				predicate = ToyundaPhone.Helpers.PredicateBuilder.And(predicate, s => s.SearchText.Contains(tmpKeyword));
			}
			songList.EmptyText = "Chargement en cours…";
			Songs = songEnumHelper.GetEnumerator((Application.Current as App).SongDatabase.Songs.Where(predicate).OrderBy(s => s.Work).ThenBy(s => s.Title));
			songEnumHelper.NotifyUpdate();
		}

		#region INotifyPropertyChanged Members

		public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

		#endregion

		public IEnumerable<ToyundaPhone.Database.Song> Songs { get; private set; }
		public IEnumerable<Database.Playlist> Playlists { get; private set; }

		private void OnPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
			}
		}

		private void Favorites_Click(object sender, EventArgs e)
		{
			NavigationService.Navigate(new Uri("/favorites", UriKind.Relative));
		}

		private void Playlists_Click(object sender, EventArgs e)
		{
			NavigationService.Navigate(new Uri("/playlists", UriKind.Relative));
		}

		Action _playlistSelectCallback = null;

		private void SongList_SelectPlaylist(object sender, Controls.SelectPlaylistEventArgs e)
		{
			_playlistSelectCallback = e.Callback;
			listPicker.Open();
		}

		private void ChooseList_Click(object sender, EventArgs e)
		{
			_playlistSelectCallback = null;
			listPicker.Open();
		}

		private void ListPicker_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
		{
			songList.Playlist = listPicker.SelectedItem as Database.Playlist;
			if (_playlistSelectCallback != null)
				_playlistSelectCallback();
		}

		private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
		{
			Microsoft.Phone.Shell.SystemTray.SetIsVisible(this, e.Orientation == PageOrientation.Portrait || e.Orientation == PageOrientation.PortraitUp || e.Orientation == PageOrientation.PortraitDown);
		}

		private void About_Click(object sender, System.EventArgs e)
		{
			NavigationService.Navigate(new Uri("/about", UriKind.Relative));
		}
	}
}